package com.sdp.wz.handleImpl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.sdp.core.bizc.utils.ApplicationContextUtils;
import com.sdp.core.bizc.vo.BusinessContext;
import com.sdp.wz.db.wz_input.entity.WzInput;
import com.sdp.wz.db.wz_input.service.IWzInputService;
import com.sdp.wz.db.wz_input_detail.entity.WzInputDetail;
import com.sdp.wz.db.wz_input_detail.service.IWzInputDetailService;
import com.sdp.wz.db.wz_now_num.entity.WzNowNum;
import com.sdp.wz.db.wz_now_num.service.IWzNowNumService;
import com.sdp.wz.db.wz_output.entity.WzOutput;
import com.sdp.wz.db.wz_output.service.IWzOutputService;
import com.sdp.wz.db.wz_output_detail.entity.WzOutputDetail;
import com.sdp.wz.db.wz_output_detail.service.IWzOutputDetailService;
import com.sdp.wz.db.wz_output_wz.entity.WzOutputWz;
import com.sdp.wz.db.wz_serial_code.service.IWzSerialCodeService;
import com.sdp.wz.db.wz_warehouse_info.entity.WzWarehouseInfo;
import com.sdp.wz.db.wz_warehouse_info.service.IWzWarehouseInfoService;
import com.sdp.wz.handle.WzInOutPutHandle;
import com.sdp.wz.utils.CurrentLoginEmp;
import com.sdp.wz.utils.WzConstants;
import com.sdp.wz.view.WzInputView;

import cn.hutool.core.bean.BeanUtil;

@Component
public class WzBarCodeOutputHandleImpl extends WzInOutPutHandle{

	@Autowired
	private CurrentLoginEmp currentLoginEmp;
	
	@Autowired
	private IWzWarehouseInfoService iWzWarehouseInfoService;

	@Autowired
	private IWzSerialCodeService iWzSerialCodeService;
	
	@Autowired
	private IWzNowNumService iWzNowNumService;
	
	@Autowired
	private IWzOutputDetailService iWzOutputDetailService;
	
	@Autowired
	private IWzOutputService iWzOutputService;
	
	@Autowired
	private IWzInputDetailService iWzInputDetailService;
	
	@Autowired
	private IWzInputService iWzInputService;
	
	@Override
	public BusinessContext execute(BusinessContext businessContext) {
		return ApplicationContextUtils.getBean(WzBarCodeOutputHandleImpl.class).wzBarCodeOutput(businessContext);
	}
	
	@Transactional(rollbackFor=Exception.class)
	public BusinessContext wzBarCodeOutput(BusinessContext businessContext) {
		//检测是否登录
		JSONObject emp = currentLoginEmp.getCurrentLoginInfo();
		if(StringUtils.isEmpty(emp)) {
			businessContext.setMessage("请先登录系统");
			businessContext.setSuccess(false);
			return businessContext;
		}
			
		List<WzOutputWz> wzList = businessContext.get(WzOutputWz.class);
		WzOutput output = businessContext.get(WzOutput.class);
		
		//检查物资是否存在
		if(output==null || wzList==null || wzList.size()==0) {
			businessContext.setSuccess(false);
			businessContext.setMessage("出库信息为空，不能入库");
			return businessContext;
		}
		
		
		WzWarehouseInfo warehouseInfo = iWzWarehouseInfoService.queryWarehouseInfoByCode(output.getWarehouseCode());
		
		//检查仓库是否停用
		if(warehouseInfo==null || WzConstants.否.getCode().equals(warehouseInfo.getIsUse())) {
			businessContext.setMessage("此仓库已停用，不能出库");
			businessContext.setSuccess(false);
			return businessContext;
		}
		
		//检查仓库是否锁定
		if(warehouseInfo==null || WzConstants.是.getCode().equals(warehouseInfo.getIsLock())) {
			businessContext.setMessage("仓库目前处于盘存状态，已锁定，无法进行出库");
			businessContext.setSuccess(false);
			return businessContext;
		}
		
		//检测是否有权限
		if(StringUtils.isEmpty(warehouseInfo.getWarehouseManagement())) {
			businessContext.setMessage("此仓库未配置库管人员");
			businessContext.setSuccess(false);
			return businessContext;
		}
		//检测是否有权限
		String[] managements =  warehouseInfo.getWarehouseManagement().split(",");
		boolean contains = Arrays.asList(managements).contains(emp.getString("empNo"));
		if(!contains) {
			businessContext.setMessage("您没有此仓库的出库权限");
			businessContext.setSuccess(false);
			return businessContext;
		}
		
		//将物资和出库数量放入MAP中，后面需要进行库存对比
		Map<String,BigDecimal> outputNumMap = new HashMap<>();
		
		//备份一份，最后更新库存
		Map<String,BigDecimal> backUpOutputNumMap = new HashMap<>();
		
		//出库的物资编码，后面用来与库存进行对比，判断出库物资是否在库存中
		Map<String,String> outputWzNoMap = new HashMap<>();
		

		
		//验证下是否有重复的物资
		Set<String> wzNos = new HashSet<String>();
		for(WzOutputWz wz : wzList) {
			wzNos.add(wz.getWzNo());
			outputNumMap.put(wz.getWzNo(),wz.getOutputNum());
			outputWzNoMap.put(wz.getWzNo(), wz.getWzNo());
		}
		
		//备份一下，后面更新库存时候需要用到
		BeanUtil.copyProperties(outputNumMap, backUpOutputNumMap);
				
		List<String> wzNoList = new ArrayList<String>(wzNos);
		if(wzNoList.size()!=wzList.size()) {
			businessContext.setMessage("出库单中可能存在重复物资");
			businessContext.setSuccess(false);
			return businessContext;
		}
		
		
		//验证库存
		List<WzNowNum> wzNowNumList = iWzNowNumService.queryWzNowNumByWzCodes(wzNoList, output.getWarehouseCode());
		if(wzNowNumList==null || wzNowNumList.size()==0) {
			businessContext.setSuccess(false);
			businessContext.setMessage("库存信息为空，无法验证库存，不能出库！");
			return businessContext;
		}
		
		//验证出库物资是否都有库存信息
		for(WzNowNum nowNum : wzNowNumList) {
			if(outputWzNoMap.containsKey(nowNum.getWzNo())) {
				outputWzNoMap.remove(nowNum.getWzNo());
			}
		}
		if(outputWzNoMap.size()>0) {
			StringBuffer wzNo=new StringBuffer("");
			for (String key : outputWzNoMap.keySet()) {
				wzNo.append(key);
				wzNo.append(",");
			}
			businessContext.setSuccess(false);
			businessContext.setMessage("物资编码《"+wzNo.deleteCharAt(wzNo.length()-1)+"》未在此仓库中有库存信息，请确认");
			return businessContext;
		}
		

		//检查库存是否满足出库
		for(WzNowNum wz : wzNowNumList) {
			if(outputNumMap.containsKey(wz.getWzNo())) {
				if(outputNumMap.get(wz.getWzNo()).compareTo(wz.getNowNum())>0) {
					businessContext.setSuccess(false);
					businessContext.setMessage("物资编码《"+wz.getWzNo()+"》出库数量:"+outputNumMap.get(wz.getWzNo())+"大于库存数量:"+wz.getNowNum()+"，不能出库！");
					break;
				}
			}
		}
		
		if(!businessContext.isSuccess()) {
			return businessContext;
		}
		
		
		LocalDateTime now = LocalDateTime.now();
		if(output.getOutputTime()==null) {
			output.setOutputTime(now);
		}
		if(output.getOutputDate()==null) {
			output.setOutputDate(output.getOutputTime().toLocalDate());
		}
		
		if(output.getCreateTime()==null) {
			output.setCreateTime(now);
		}
		
		//生成出库单号
		if(StringUtils.isEmpty(output.getOutputCode())) {
			String serialCode = iWzSerialCodeService.createSerialCode(WzConstants.流水号前缀_物资出库单.getCode());
			if(StringUtils.isEmpty(serialCode)) {
				businessContext.setMessage("出库单号生成失败，请稍后再试");
				businessContext.setSuccess(false);
				return businessContext;
			}
			output.setOutputCode(serialCode);
		}
		
		output.setOpName(emp.getString("empName"));
		output.setOpNo(emp.getString("empNo"));
		output.setIsUse(WzConstants.是.getCode());
		
		
		//要修改的入库单信息
		List<WzInputDetail> wzInputDetailList = new ArrayList<>();
		//需要修改的入库单主表的编号map
		Map<String, String> wzInputCodeMap = new HashMap<>();
		
		List<WzOutputDetail> wzOutputDetailList = new ArrayList<>();
		
		QueryWrapper<WzInputView> queryWrapper = new QueryWrapper<>();
		queryWrapper.in("b.wz_no", wzNoList);
		queryWrapper.eq("a.warehouse_code", output.getWarehouseCode());
		queryWrapper.orderByAsc("a.input_time");
		iWzInputDetailService.queryInputInfo(queryWrapper, new ResultHandler<WzInputView>() {
			WzInputView inputView = null;
			WzInputDetail wzInputDetail = null;
			WzOutputDetail wzOutputDetail = null;
			@Override
			public void handleResult(ResultContext<? extends WzInputView> resultContext) {
				if(outputNumMap.size()==0) {
					resultContext.stop();
				}
				inputView = resultContext.getResultObject();
				if(outputNumMap.containsKey(inputView.getWzNo())) {
					
					wzInputDetail = new WzInputDetail();
					
					if(outputNumMap.get(inputView.getWzNo()).compareTo(BigDecimal.ZERO)>0) {
						wzOutputDetail = new WzOutputDetail();
						BeanUtil.copyProperties(inputView, wzOutputDetail);
						wzOutputDetail.setInputDetailId(inputView.getKeyId());
						wzOutputDetail.setCreateTime(now);
						wzOutputDetail.setKeyId(null);
						if(outputNumMap.get(inputView.getWzNo()).compareTo(inputView.getNowNum())>0) {
							//如果说，出库数量大于这条记录的当前库存
							wzOutputDetail.setOutputNum(inputView.getNowNum());
							
							//将出库数量减去当前库存
							outputNumMap.put(inputView.getWzNo(), outputNumMap.get(inputView.getWzNo()).subtract(inputView.getNowNum()));
						
							//将当前库存数量变为0
							BeanUtil.copyProperties(inputView, wzInputDetail);
							wzInputDetail.setNowNum(BigDecimal.ZERO);
							wzInputDetailList.add(wzInputDetail);
							//添加待修改的入库单编号
							wzInputCodeMap.put(wzInputDetail.getInputCode(), wzInputDetail.getInputCode());
						}else {
							//出库数量小于当前库存
							//设置 出库数量
							wzOutputDetail.setOutputNum(outputNumMap.get(inputView.getWzNo()));

							//修改当前库存
							BeanUtil.copyProperties(inputView, wzInputDetail);
							wzInputDetail.setNowNum(inputView.getNowNum().subtract(outputNumMap.get(inputView.getWzNo())));
							wzInputDetailList.add(wzInputDetail);
							//添加待修改的入库单编号
							wzInputCodeMap.put(wzInputDetail.getInputCode(), wzInputDetail.getInputCode());

							//将出库数量变为0
							outputNumMap.put(inputView.getWzNo(), BigDecimal.ZERO);
							//将出完的物资删除
							outputNumMap.remove(inputView.getWzNo());
						}
						
						wzOutputDetailList.add(wzOutputDetail);
					}
					
					
				}
			}
		});
		
		if(wzOutputDetailList.size()>0) {
			for(WzOutputDetail wz : wzOutputDetailList) {
				wz.setOutputCode(output.getOutputCode());				
			}
		}
		
		if(wzInputDetailList.size()>0) {
			iWzInputDetailService.updateBatchById(wzInputDetailList);
			//更新入库单的是否出库字段
			UpdateWrapper<WzInput> updateWrapper = new UpdateWrapper<>();
			updateWrapper.lambda().in(WzInput::getInputCode, new ArrayList<String>(wzInputCodeMap.values()))
				.set(WzInput::getIsOutput, WzConstants.是.getCode());
			iWzInputService.update(updateWrapper);
		}
		
		iWzOutputService.updateById(output);
		iWzOutputDetailService.saveBatch(wzOutputDetailList);
		
		//更新库存
		iWzNowNumService.wzNowNumSubtract(wzNoList, backUpOutputNumMap,warehouseInfo);
		
		return businessContext;
	}

}
